<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
	<meta http-equiv="pragma" content="no-cache" />
    <meta name="author" content="Jayli" />
	<meta name="keywords" content="淘宝UED 前端工程师 拔赤" />	
	<meta name="description" content="淘宝前端工程师拔赤，关注尖端前端技术，关注yui" />
	<meta http-equiv="imagetoolbar" content="no" />
	<meta name="title" content="拔赤的文章列表" />
    <title>[翻译]YUI3.4.0 中对 Seed 和 Loader 的改造</title>
    <link href="http://jayli.github.com/blog/atom.xml" rel="alternate" title="setImpl" type="application/atom+xml" />
    <link rel="stylesheet" href="http://jayli.github.com/blog/media/css/style.css">
    <link rel="stylesheet" href="http://jayli.github.com/blog/media/css/github.css">
	<style>
	</style>
    <script type="text/javascript" src="http://jayli.github.com/blog/media/js/highlight.pack.js"></script>
    <script type="text/javascript">
      hljs.initHighlightingOnLoad();
    </script>
	<!--[if lte IE 8]>
	<script src="http://a.tbcdn.cn/apps/lottery/00023/index-v3/js/html5.js"></script>
	<![endif]-->
	<meta name="baidu-tc-verification" content="afb6c9df553ef3493d9ee65263df0d55" />
	<script src="http://siteapp.baidu.com/static/webappservice/uaredirect.js" type="text/javascript"></script><script type="text/javascript">uaredirect("http://m.zoojs.org", "http://jayli.github.com/blog");</script>
  </head>
  <body>
    <div id="container">
      <div id="main" role="main">
        <header>
        <h1>[翻译]YUI3.4.0 中对 Seed 和 Loader 的改造</h1>
        </header>
        <nav>
        <span><a title="home page" class="" href="/blog/index.html">home</a></span>
        <span><a title="tags" class="" href="/blog/tags.html">tags</a></span>
        <span><a title="about" class="" href="/blog/about.html">about me</a></span>
        <span><a title="flickr" class="" href="http://www.flickr.com/photos/lijing00333">flickr</a></span>
        <span><a title="blogroll" class="" href="/blog/links.html">links</a></span>
        <span><a title="projects" class="" href="/blog/projects.html">projects</a></span>
        <span><a title="subscribe me" class="" href="/blog/atom.xml">feed</a></span>
        </nav>
        <article class="content">
        <section class="post">
<ul>
<li>原文：http://www.yuiblog.com/blog/2011/07/01/yui-and-loader-changes-for-3-4-0/</li>
<li>标题：YUI and Loader changes for 3.4.0</li>
<li>作者：Dav Glass</li>
<li>译文：YUI3.4.0 中对 Seed 和 Loader 的改造</li>
</ul>


<p>在 YUI3.4.0 中，我们开始对 Loader 的核心逻辑进行升级改造。Loader 的性能有了很大提升，而且更加健壮，可以在更多场景下非常方便的使用（比如在服务器环境中）。同时我们会给出YUI的发展路线图，但首先还是有必要解释一下本次更新带来了哪些新内容，为什么做这些更新，以及这些更新对开发者带来的影响。对于大多数用例来说，开发者甚至不会察觉到有什么变化，但有一点变化最明显，就是速度更快，而且加载的资源文件更小了。</p>

<p>种子文件</p>

<p>我们首先来看 YUI 种子文件的一些变化，在之前的版本中，YUI 种子文件非常小，不包含 Loader 以及它的元组件（meta-data）。我们发现在90%的用例中，种子文件并未像我们设计的那样工作。大部分人引用种子文件之后再去载入他们自有的模块，也就意味着种子文件需要先获取 Loader，再计算模块依赖关系，然后再载入模块。我们感到这种策略是一种错误，它会带来一次额外的 http 请求，因此在新版的 YUI 中我们将 Loader 和它的元组件都整合进种子文件中。当然，这会让种子文件体积变大一些，但由于元组件已经包含在种子之内，页面模块的加载自然会提速很多。</p>

<p>如果你仍希望使用旧的方式加载YUI，你只需引入 yui-base 种子文件就可以了。基于 yui-base 可以单机模式运行YUI，它也可以根据需要去自动加载 Loader。如果你想更细粒度的使用 YUI，我们提供了 yui-core 种子文件，yui-core 文件几乎就是原来的 yui-base。</p>

<pre><code>/build/yui/yui-min.js //YUI Seed + Loader
/build/yui-base/yui-base-min.js //Old YUI Seed with Loader fetch support
/build/yui-core/yui-core-min.js //Old yui-base without Loader fetch support
</code></pre>

<p>注意，这些URL和之前的URL有所不同。如果想使用 yui/yui-base.js 文件，则需要重新定位至 yui-core/yui-core.js，如果你想使用旧的方式来加载种子和 Loader，则需要使用 yui-base/yui-base.js 种子文件。</p>

<p>促使我们对 YUI 作这种调整的另一个重要原因是，根据 YUI 的发展路线图，我们需要 YUI 将来运行于各种平台上。如果你有 combo 服务器（译注：combo 是合并的意思，这里指可以在服务器端合并脚本的服务器），则旧有的种子外加 Loader 的使用方式是ok的，我们可以将种子和 Loader 合并入一个 http 请求。那么 YUI 如何运行在服务器端、离线应用程序以及手持终端里呢？这些场景所需的种子文件需要做到最小化，同时又要保持各自所需的功能。</p>

<p>模块依赖计算器（Rullups）</p>

<p>（译注：YUI 提供了两种模块粒度，粗粒度和细粒度，分别面向初级开发者和高级开发者使用。比如 event 中就包含了 event-key 和 event-move 等子模块，这里所说的“模块依赖计算”不是“向下”计算而是“向上”计算，比如我引用了 event-key，计算器得知它属于 event 大模块，这时就会加载 event，而放弃加载 event-key，由于 event 是很多小模块合写在一起的，因此可能会载入不需要的功能）</p>

<p>接下来，我们将模块依赖计算器从 core 中删除掉了，同时将 Loader 中的 allowRollup 属性默认值设为 false。这意味着什么？希望它不会带来任何影响！在解释这个更新造成的影响之前，我们首先解释下背后的原因。还是“性能”——模块加载的负担过重。来看这个例子：</p>

<pre><code>Module A: requires event-a, event-b
Module B: requires event-c, event-d
</code></pre>

<p>在 YUI3.4.0 之前版本中的“模块依赖计算器”是用来决定还需加载哪些子模块，当同时加载这两个模块时，比如这个例子中通过计算得知需要加载 event 模块，这个模块包含：</p>

<pre><code>event.a, event.b, event.c, event.d, event.e, event.f, event.g, event.h
</code></pre>

<p>其实所载入的这些模块有些并不是我们真正需要的。如果关掉“模块依赖计算器”，YUI 将只会请求实际引用的模块，而不会去请求更多。多数情况下你不会注意到这些，如果你是模块的开发者，则可能会遇到一些麻烦，之前运行好好的模块现在不能运行了，其实是之前他们只是“碰巧”可以运行而已。来看一个实际的例子，Dial：</p>

<p>在3.3.0中，Dial引用了这些：</p>

<pre><code>requires: [
    'widget',
    'dd-drag',
    'substitute',
    'event-mouseenter',
    'transition',
    'intl'
]
</code></pre>

<p>对于大多数场景来说，Dial 在 3.4.0 下可以照常工作，但不支持键盘事件。在简单分析之后发现，“模块依赖计算器”实际上请求了整个 Event 模块（包括event-move和event-key）。YUI3.4.0 中关掉了“模块依赖计算器”，Dial 也不再去请求 event-move 子模块所属的母模块 event。为了让 Dial 的模块引用更加细致有针对性，则需要引用所有实际用到的小模块，这样代码才会正常工作：</p>

<pre><code>requires: [
    'widget',
    'dd-drag',
    'substitute',
    'event-mouseenter',
    'event-move',
    'event-key',
    'transition',
    'intl'
]
</code></pre>

<p>对于模块开发者来说，清楚的知道自己的组件所依赖哪些模块非常重要，这也是比较好的习惯和实践。不要想当然去引用“上游模块”（就是刚才提到的粗粒度模块），始终确保只引用了真正需要的模块。</p>

<p>这也意味着模块引用的定义更加合理，比如，datatype-date 内置支持全球化格式的数据，在之前的版本中这样使用：</p>

<pre><code>Y.Intl.getAvailableLangs('datatype-date');
</code></pre>

<p>但这个模块并不真正包含某种语言（datatype-date-format 模块包含）。因此需要指定正确的模块引用：</p>

<pre><code>Y.Intl.getAvailableLangs('datatype-date-format');
</code></pre>

<p>编译规则的修改和删除子模块</p>

<p>除此之外，接下来的更新是修改了编译后的文件目录并从core中删除子模块。其实子模块并没有真正删除，只是元模块数据结构改变了。它使得当前 YUI 可以向后兼容。</p>

<p>core 中的子模块有很多问题，我们必须把他们一一解决掉。第一个是性能。每次计算依赖关系的时候，程序会把子模块/插件结构中的每个节点都遍历一遍。在 Loader 运行过程中大量的遍历操作会严重损耗性能。去掉了 core 中的子模块支持，可以免去大量低效的函数调用和迭代运算。</p>

<p>我们对 Loader 做了修改，以便能通过模块的元数据中属性来定义需要引用的模块，这样便可以载入我们指定的模块而不是去查找原始模块。如果你引用了“dd”（拖拽），Loader 将会把“dd”拆分成元模块（子模块），属性值看起来就像这样：</p>

<pre><code>"dd-ddm-base,dd-ddm,dd-ddm-drop,
dd-drag,dd-proxy,dd-constrain,
dd-drop,dd-scroll,dd-drop-plugin"
</code></pre>

<p>在 YUI 种子文件当中同样包含了“垂直模块依赖计算”或者称之为“别名”。模块的定义和 Loader 中的元模块是一模一样的。这样的话就可以直接根据“模块依赖配置工具”（Dependency Configurator）来获得文件的引用地址，同样也可以使用剥离出 Loader 的“模块依赖计算器”，在未来的版本发布中，我们还会对这部分功能作进一步的提炼。</p>

<p>介绍过这些更新之后，我们来看一下 YUI 的项目文件，在之前的版本中，子模块决定模块的文件路径，比如：</p>

<pre><code>"dd": {
    "submodules": {
        "dd-drag":
            // Module data
    }
}
</code></pre>

<p>在3.3.0中编译“dd”得到的文件结果是：</p>

<pre><code>/build/dd/dd-drag.js
/build/dd/dd-ddm.js
/build/dd/dd-drop.js
</code></pre>

<p>在3.4.0的新编译规则下，“dd”编译后的结果是：</p>

<pre><code>/build/dd-drag/dd-drag.js
/build/dd-ddm/dd-ddm.js
/build/dd-drop/dd-drop.js
</code></pre>

<p>这样我们就可以将模块元数据中的“path”属性删掉了，减少了文件体积，也免去了根据模块名称查找它的文件路径的工作。</p>

<p>如果你之前引用了配置好的合并了文件的（combo）URL，那么升级 YUI 到 3.4.0 后则需要重新生成这个 URL。</p>

<p>本次更新也有不足，如果你引用了合并了多个模块文件的 URL 用以对页面进行初始化，则不能只更新版本号，你需要重新到模块依赖配置工具中获得新的 URL。</p>

<p>未来</p>

<p>我们还会对YUI作进一步的提炼、重构、优化，并将 Loader 和种子文件中的各个功能点的代码体积降到最低。当然首要工作依然是将 YUI 移植到除了客户端浏览器平台之外的服务器端、命令行和手持终端的各个平台中。</p>

</section>
<section class="meta">

<!--span class="tags">
  tagged by 
  
</span-->

<span class="time">
  posted at <time datetime="2011-03-11">2011-03-11</time>
</span>
</section>

<section class="comment">
<div id="disqus_thread"></div>
<script type="text/javascript">
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'jayliblog'; // required: replace example with your forum shortname
	var disqus_identifier = 'urn:uuid:cc706484-0a98-4403-bb96-6fca169c37c9';

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</section>


        </article>
      </div>
    </div> <!--! end of #container -->
  </body>
</html>
